module command.StartAppCommand;

import std.stdio;

import std.string;
import hunt.console.helper.QuestionHelper;
import hunt.console.input.Input;
import hunt.console.input.InputArgument;
import hunt.console.output.Output;
import hunt.console.question.Question;
import hunt.console.command.Command;
import std.file;
import hunt.util.Serialize;
import config.ConfigurationDefine;
import hunt.logging;
import msgtrans;
import client.MsgServerClient;
import client.LogicServerClient;
import message.Constants;
import core.thread;
import std.conv :to ;
import message.MsgDefine;
import google.protobuf;
import std.array;
import client.GateServerClient;


class StartAppCommand : Command
{
    enum string configPath = "./config_test.json";

    __gshared string selfId ;


    static string getSelfId()
    {
            return selfId;
    }

    private MsgConfig _config;

    override protected void configure()
    {
        this
        .setName("start")
        .setDescription("Outputs a start.")
        .addArgument("config", InputArgument.OPTIONAL, "Name of the person to greet")
        ;
    }

    override protected int execute(Input input, Output output)
    {
        string name = input.getArgument("config");
        if (name is null) {
            name = "stranger";
        }
        writeln("config name: ", name);
        std.stdio.stdout.flush();
        parseConfig(name);
        writeln("config loaded.");
        std.stdio.stdout.flush();
        initLog();
        startApp();
        writeln("app statred.");
        std.stdio.stdout.flush();
        return 0;
    }

    override protected void interact(Input input, Output output)
    {
        if (input.getArgument("config") is null) {
            //string name = (cast(QuestionHelper) (getHelper("question")))
            //.ask(input, output, new Question("What is your name?"));
             input.setArgument("config", configPath);
             output.writeln(format("Not specified config use default config %s", configPath));
        }
        else
        {
            output.writeln(format("start app with config : %s", input.getArgument("config")));
        }
    }

    private void parseConfig(string path)
    {
        string data = readText(path);
        _config = toOBJ!MsgConfig(parseJSON(data));
        Config.getInstance().setConfig(_config);
        selfId = to!string(_config.id);
    }

    private void initLog()
    {
        // LogConf conf;
        // conf.fileName = Config.getInstance().getConfig().log;
        // logLoadConf(conf);
    }

    private void startApp()
    {
        writeln("start app ...");
        std.stdio.stdout.flush();

        foreach(LogicServerConf c ; _config.logicserver)
        {
            while(true)
            {
                MessageTransportClient client = new MessageTransportClient(LogicClientName);

                client.channel(new TcpClientChannel(c.host, cast(ushort)c.port));
        writeln("Logic host: ", c.host);
        std.stdio.stdout.flush();
                // client.closer((TransportContext t) {
                //     while (true)
                //     {
                //         client.connect();
                //         logInfo("isConnected: %s", client.isConnected );
                //         if(client.isConnected)
                //         {
                //             client.send(new MessageBuffer(MESSAGE.CMD_REGISTER_MSGSERVER, cast(ubyte[])(StartAppCommand.getSelfId)));
                //             break;
                //         }

                //         Thread.sleep(2.seconds);
                //     }
                // });

                try
                {
                    client.connect();
                }
                catch (Exception e)
                {
                    logError("connect to logicserver error %s", e);
                }
                std.stdio.stdout.flush();

                if(client.isConnected)
                {
                    logInfo("LogicServer is connected.");
                    client.send(new MessageBuffer(MESSAGE.CMD_REGISTER_MSGSERVER, cast(ubyte[])(to!string(_config.id))));
                    LogicServerClient.getInstance().addForwardClient(c.id, client);
                    break;
                }

                logWarning("Can't connect to LogicServer, waiting for 2 seconds.");
                std.stdio.stdout.flush();
                Thread.sleep(2.seconds);
            }

        }
        std.stdio.stdout.flush();

        initChatMap();

        MessageTransportServer server = new MessageTransportServer(MsgServerName);

        server.addChannel(new TcpServerChannel(cast(ushort)_config.tcpport));

        server.acceptor((TransportContext ctx) {
            infof("New connection: id=%d", ctx.id());
        });

        server.closer((TransportContext ctx) {
                GateServerClient.getInstance().deleForwardClient(ctx.id);
        });

        server.start();
        std.stdio.stdout.flush();

        foreach(MsgServerConf c ; _config.msgserver)
        {
            if (_config.id == c.id)
            {
                logInfof("config.id: %d c.id : %d",_config.id,c.id);
                std.stdio.stdout.flush();
                MsgServerClient.getInstance.addForwardClient(c.id,null);
                continue;
            }

            while (true) {
                MessageTransportClient client = new MessageTransportClient(MsgClientName);
                logInfo("Connecting to MsgServer host(%s) port(%d)", c.host, c.port);
                client.channel(new TcpClientChannel(c.host, cast(ushort)c.port));
                client.connect();

                logInfo("MsgServer connected???");
                if (client.isConnected)
                {
                    logInfo("MsgServer is connected.");
                    client.send(new MessageBuffer(MESSAGE.CMD_REGISTER_MSGSERVER , []));
                    MsgServerClient.getInstance.addForwardClient(c.id,client);
                    break;
                }

                logWarning("Can't connect to MsgServer, waiting for 2 seconds.");
                Thread.sleep(2.seconds);
            }
            std.stdio.stdout.flush();
        }
    }

    private void initChatMap()
    {
        int index = selfHashIndex();
        g_msgServerIndex = index;
        MessageTransportClient logicClient = LogicServerClient.getInstance().getForwardClient();
        InitChatMap req = new InitChatMap();
        req.index = index;
        req.size = cast(int)(_config.msgserver.length);
        g_msgServerSize = req.size;
        logicClient.send(new MessageBuffer(MESSAGE.CMD_INITCHATMAP, req.toProtobuf.array));
        logInfof("send initChatMap request ----- server index: %d, servers size: %d", req.index, req.size);
        std.stdio.stdout.flush();
    }

    private int selfHashIndex()
    {
        int i = 0;
        foreach (MsgServerConf c ; _config.msgserver)
        {
            if (_config.id == c.id)
            {
                    break;
            }
            i++;
        }
        return i;
    }
}
